package com.xxxtea.component;

import cn.hutool.core.lang.ansi.AnsiColor;
import cn.hutool.core.lang.ansi.AnsiEncoder;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.TypeHandlerRegistry;

import java.sql.Statement;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;

/**
 * MyBatis SQL打印拦截器
 * 
 * 拦截MyBatis的SQL执行，打印实际执行的SQL语句（带参数值），便于开发调试和排查问题。
 * 支持update和query方法，自动格式化SQL并高亮显示。
 * 
 * @author badman
 * @since 1.0.0
 */
@Slf4j
@Intercepts({
		@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
		@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})
})
public class SqlPrintInterceptor implements Interceptor {
	/**
	 * 拦截SQL执行，打印实际SQL
	 * @param invocation MyBatis拦截器调用对象
	 * @return 执行结果
	 * @throws Throwable 异常
	 */
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		try {
			// 获取SQL语句
			StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
			BoundSql boundSql = statementHandler.getBoundSql();
			Object parameterObject = boundSql.getParameterObject();
			List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
			// 替换参数值并打印
			if (parameterMappings != null && parameterObject != null) {
				Configuration configuration = SpringUtil.getBean(SqlSessionFactory.class).getConfiguration();
				log.info("Actual SQL: {}", AnsiEncoder.encode(AnsiColor.BRIGHT_YELLOW, formatSql(configuration, boundSql)));
			}
		} catch (Exception e) {
			log.error("未知异常", e);
		}
		// 继续执行
		return invocation.proceed();
	}

	/**
	 * 格式化SQL，将?替换为实际参数值
	 * @param configuration MyBatis配置
	 * @param boundSql 绑定SQL对象
	 * @return 格式化后的SQL
	 */
	private String formatSql(Configuration configuration, BoundSql boundSql) {
		Object parameterObject = boundSql.getParameterObject();
		List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
		String sql = boundSql.getSql().replaceAll("\\s+", " ");

		if (parameterMappings == null || parameterObject == null) {
			return sql;
		}
		TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
		for (ParameterMapping parameterMapping : parameterMappings) {
			String propertyName = parameterMapping.getProperty();
			Object value;

			if (boundSql.hasAdditionalParameter(propertyName)) {
				value = boundSql.getAdditionalParameter(propertyName);
			} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
				value = parameterObject;
			} else {
				MetaObject metaObject = configuration.newMetaObject(parameterObject);
				value = metaObject.getValue(propertyName);
			}

			String parameterValue;
			if (value instanceof String) {
				parameterValue = "'" + value + "'";
			} else if (value instanceof Date) {
				DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);
				parameterValue = "'" + dateFormat.format(value) + "'";
			} else {
				parameterValue = value != null ? value.toString() : "null";
			}

			sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(parameterValue));
		}
		return sql;
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
	}
}